#pragma once
#include <windows.h>
#include <WindowsX.h>
#include <tchar.h>
#include <list>
#include <vector>


#include "interfaces.h"
#include "EventManager.h"
#include "Geometry.h"
#include "HumanView.h"
#include "ResourceCache\ResourceCache.h"
#include "Actors.h"
#include "AssetManager.h"
#include "RendererDX9Main.h"
#include "WindowsFramework.h"
#define RE() RandomEngineApp::Get()
#define REC() RandomEngineApp::Get()->GetResCache()
#define REA() RandomEngineApp::Get()->GetAssetManager()
#define REL() RandomEngineApp::Get()->GetLogic()
#define RER() RandomEngineApp::Get()->GetRenderer()
class __single_inheritance RandomEngineApp
{
public:
	RandomEngineApp();
	~RandomEngineApp();
	//2 step initialization
	int RunEngine(HINSTANCE hInstance, LPWSTR lpCmdLine, unsigned int screenWidth, unsigned int screenHeight, bool FullScreen, _TCHAR* window_name);
	//Class Specific Stuff
	const TCHAR* VGetName();
	static RandomEngineApp * const Get();
	IRenderer * const GetRenderer();
	IResCache * const GetResCache();
	IAssetManager * const GetAssetManager();
	void LoadEngineResources();
	void ReleaseEngineResources(bool OnlyBuffers);

	virtual LogicPtr CreateGameAndView() = 0;
	
	bool OnUpdate(float deltaTime);
	bool OnRender(float deltaTime);
	void OnLostDevice();
	void OnResetDevice();
	void OnCreateDevice();
	void OnDestroyDevice();

	//---------------------------------------------------------------------------------------------------------------------
	//General Purpose Functions
	//---------------------------------------------------------------------------------------------------------------------
	LogicPtr const GetLogic();
	const std::string & GetLogDirectory();
	void SetLogDirectory(const std::string & dir);
	const double GetTimeElapsed();
	const float GetFrameTime();
	void FrameTick(const float frame_time); //This will not effect execution of the engine. However it will affect the results returned by GetTime functions
protected:
	//---------------------------------------------------------------------------------------------------------------------
	//General Purpose Variables
	//---------------------------------------------------------------------------------------------------------------------
	float m_FrameTime;	// time elapsed since last frame
	double m_ElapsedTime;	// time elapsed since instance created
	std::wstring LogDirectory;
	std::wstring ApplicationDir;
	std::wstring ApplicationName;
	bool m_bQuitting;
protected:
	//---------------------------------------------------------------------------------------------------------------------
	//Engine Systems
	//---------------------------------------------------------------------------------------------------------------------
	LogicPtr m_logic; 
public:
	OSFrameworkPtr m_OSFramework;
	ResCachePtr m_ResCache;
	AssetManagerPtr m_AssetManager;
	RendererPtr m_Renderer;
};


//////////////////////////////////////////////////////////////////////////////////////////////
/////////
/////////	Base Game Logic
/////////
class BaseLogicListener;
class BaseGameLogic: public IGameLogic
{
public:
	BaseGameLogic();
	~BaseGameLogic();

	GameViewList m_GameViewList;
	ActorMap m_ActorMap;
	EventListenerPtr m_Listener;
public:
	virtual void VAddView(GameViewPtr view);
	virtual void VRemoveView(GameViewPtr view);

	virtual ActorId VGenerateActorId();
	virtual void VAddActor(ActorPtr actor);
	virtual void VRemoveActor(const ActorId id);
	virtual void VMoveActor(const ActorId id, const Vec3 & dir);
	virtual ActorPtr VGetActor(const ActorId id);

	virtual void VOnRender();
	virtual void VOnUpdate(float fTime);
	virtual void VHandleEvent(EventDataPtr EventData);

	virtual bool VBuildInitialScene();
	virtual bool VLoadScene(AssetDataPtr level);
	virtual bool VClearScene();
private:
	ActorId m_currentid;
};


class BaseLogicListener : public IEventListener
{
public:
	BaseLogicListener(BaseGameLogic * logic) : m_Logic(logic) {}
	~BaseLogicListener() {}
	virtual void HandleEvent(EventDataPtr EventData);
	BaseGameLogic * m_Logic;
};